# THIS FILE IS LICENSED UNDER THE MIT LICENSE AS OUTLINED IMMEDIATELY BELOW: 
#
# Permission is hereby granted, free of charge, to any person obtaining a
# copy of this software and associated documentation files (the "Software"),  
# to deal in the Software without restriction, including without limitation  
# the rights to use, copy, modify, merge, publish, distribute, sublicense,  
# and/or sell copies of the Software, and to permit persons to whom the  
# Software is furnished to do so, subject to the following conditions:
#
# The above copyright notice and this permission notice shall be included in 
# all copies or substantial portions of the Software.
#
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 
# FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER 
# DEALINGS IN THE SOFTWARE.

# drivers.py
# Copyright (C) 2007 Devion, contributors.
# written by: 
#     Jan Jokela (jan@devion.org)

"""
Contains all the drivers which will do the work of playing back
the audio objects. This is the "low level" layer, with the real
backend implementations.

Currently contains:
    * Pygame 
    * Gstreamer
"""

__version__ = 0.2
__doc__ = 'Audio Drivers'

import os.path, sys, time, threading, traceback, wave

import pygst
pygst.require("0.10")
import gst

class Pygame:
   """The Pygame backend.

   It plays back several types of audio files (mp3, ogg/vorbis, ...),
   though not all that would be desirable. It only plays back MPEG
   type movie files.

   It has the pleasant advantage of not requiring external libraries,
   other than the one that the User Interface itself uses (Pygame).
   """

   def __init__(self):
      import pygame.mixer
      #pygame.mixer.init()
      self.music = None

   def play(self, music=None):
      """Plays back a given media object.

      It plays back no matter what. If no file is given, it unpauses
      if necessary to resume playback. If a file is given and equals
      the current one, it does nothing (unless that same file is
      paused or stopped). If a file is given, it stops the current
      file being played and starts the with the new one.

      Keyword arguments:
      music (media.object.Audio) -- The music to play back. (default: None)

      """
      if self.music == music and pygame.mixer.music.get_busy() == 1:
         if self.is_playing == False:
            pygame.mixer.music.unpause()
         else:
            self.music = music
            print music.uri
            pygame.mixer.music.load(music.uri)
            pygame.mixer.music.play()
         self.is_playing = True

   def pause(self):
      """Pause the playback or resume if already paused."""
      if self.is_playing == True:
         pygame.mixer.music.pause()
         self.is_playing = False
      else:
         pygame.mixer.music.unpause()
         self.is_playing = True

   def stop(self):
      """Completely stop the playback."""
      pygame.mixer.music.stop()
      self.is_playing = False

   def elapsed_time(self):
      """The time it has elapsed since the playback's last full stop.

      The method returns a float (seconds.miliseconds), representing
      how long the file has been playing.

      """
      return pygame.mixer.music.get_pos()

   def seek(self, value):
      """Changes the pointer's location for playback and resumes it.

      After the method is called, it changes the pointer's position
      to the given value (a float, being seconds.miliseconds), and
      immediatly resumes the playback according to the given value.

      Keyword arguments:
      value (float) -- The pointer's new position.

      """
      pygame.mixer.music.play(0, float(value))


class Pymedia:
    """ The Pymedia backend """
    def __init__(self):
        #import bPlayer
        #self.player = bPlayer.Core(1)
        pass
    
    def play(self, music=None):
        #self.player.play(music)
        pass
        
class Gstreamer:
    """ The Gstreamer backend """
    def __init__(self):
        self.music = None
        self.state = gst.STATE_NULL
        self.__length = 1
        self.player = gst.element_factory_make("playbin", "player")
        fakesink = gst.element_factory_make('fakesink', "my-fakesink")
        self.player.set_property("video-sink", fakesink)
        bus = self.player.get_bus()
        bus.add_signal_watch()
        bus.connect('message', self.on_message)
        
    def play(self, music=None):
        if os.path.exists(music):
            self.music = music
            self.player.set_property('uri', "file://" + self.music)
            self.player.set_state(gst.STATE_PLAYING) 
            self.state = gst.STATE_PLAYING
    
    def pause(self):
        self.state = gst.STATE_PAUSED
        self.player.set_state(gst.STATE_PAUSED)
    
    def stop(self):
        self.state = gst.STATE_NULL
        self.player.set_state(gst.STATE_NULL) 
        
    def seek(self, pos):
        """now = self.player.query_position(gst.FORMAT_TIME)[0]
        seek_ns = now + (10 * 1000000000)"""
        if pos < 0: pos = 0
        if pos > self.get_duration() * 1000000: pos = self.get_duration() * 1000000
        self.player.seek_simple(gst.FORMAT_TIME, gst.SEEK_FLAG_FLUSH, pos)
        
    def increment_volume(self, step=3):
        self.player.volume = step
        
    def decrement_volume(self, step=3):
        self.player.volume = step  

    def set_volume(self, volume):
        """ Set the volume level of the gst playbin. between 0 and 100%        """
        if int(volume) in range(101) and self._stream:
            volume = int(volume)
        #self.logger.info("Setting volume to %s" % volume)
        item = self.get_current_item()
        if item is not None:
            item.set_volume(volume)
            settings_signal.emit('volume', volume)
            volume = (volume * 10) / 100.
            if volume < 0.:
                volume = 0.
            elif volume > 10.:
                volume = 10.
            self._stream.volume = volume

    def get_media(self):
        return self.music

    def get_paused(self):
        if self.state == gst.STATE_PAUSED:
            return True
        else: return False

    def get_duration(self):
        if self.player.get_property('uri'):
            try: p = self.player.query_duration(gst.FORMAT_TIME, None)[0]
            except gst.QueryError: p = 0
            p //= gst.MSECOND
            return p
        else: return 0
        
    def get_position(self):
        if self.player.get_property('uri'):
            try: p = self.player.query_position(gst.FORMAT_TIME)[0]
            except gst.QueryError: p = 0
            p //= gst.MSECOND
            return p
        else: return 0
        
    def on_message(self, bus, message):
        t = message.type
        if t == gst.MESSAGE_EOS:
            self.player.set_state(gst.STATE_NULL)
        elif t == gst.MESSAGE_ERROR:
            self.player.set_state(gst.STATE_NULL)
            

    